package com.qd.core.aspect.datascope;

import com.cdqidi.util.AnnotationUtil;
import com.cdqidi.util.page.BaseQuery;
import com.cdqidi.util.sql.SqlParam;
import com.qd.common.sys.annotation.DataScope;
import com.qd.common.sys.domain.entity.role.RoleDTO;
import com.qd.common.sys.domain.login.LoginUser;
import com.qd.common.sys.enums.DataScopeType;
import com.qd.common.sys.util.SecurityUtils;
import com.qd.system.service.user.UserOperatorService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 权限验证
 *
 * @author sjk
 */
@Aspect
@Component
@Slf4j
public class DataScopeAspect {
    /**
     * 定义切入点
     */
    @Pointcut("@annotation(com.qd.common.sys.annotation.DataScope)")
    public void dataScopePointCut() {

    }

    @Before(value = "dataScopePointCut()")
    public void doBefore(JoinPoint joinPoint) {
        DataScope controllerDataScope = AnnotationUtil.getMethodAnnotation(joinPoint, DataScope.class);
        if (null == controllerDataScope) {
            return;
        }
        final Object[] args = joinPoint.getArgs();
        BaseQuery baseQuery;
        for (Object arg : args) {
            if (arg instanceof BaseQuery) {
                baseQuery = (BaseQuery) arg;
                build(baseQuery, controllerDataScope);
                return;
            }
        }
    }

    /**
     * 有没有通过菜单配置的部门，如果有不处理
     *
     * @param baseQuery           系统参数
     * @param controllerDataScope DataScope注解
     */
    private void build(BaseQuery baseQuery, DataScope controllerDataScope) {
        final LoginUser loginUser = SecurityUtils.getLoginUser();
        if (null == loginUser) {
            return;
        }
        Map<String, Object> sysParams = baseQuery.getSysParams();
        if (null == sysParams || sysParams.isEmpty()) {
            sysParams = new HashMap<>(1);
        }
        final SqlParam sqlParam = new SqlParam();
        final String deptAlias = controllerDataScope.orgAlias();
        final String deptIdAlias = controllerDataScope.orgIdAlias();
        if (StringUtils.hasLength(deptAlias)) {
            sqlParam.setAlias(deptAlias);
        }
        if (StringUtils.hasLength(deptIdAlias)) {
            sqlParam.setColumn(deptIdAlias);
        }
        sqlParam.setOperator(SqlParam.SQL_IN);
        String orgScope = UserOperatorService.ORG_ID;
        final String currentOrgId = loginUser.getCurrentOrgId();

        final String[] orgIds = new String[2];
        if (SecurityUtils.isAdmin(loginUser.getUserId())) {
            orgIds[0] = UserOperatorService.DB_ORG_PARENT_ID;
            orgScope = UserOperatorService.ORG_IDS;
        } else {
            final List<RoleDTO> roles = loginUser.getUser().getRoles();
            if (null == roles || roles.isEmpty()) {
                orgIds[0] = UserOperatorService.DB_ORG_ID;
            } else {
                final long count = roles.stream().filter(role -> role.getDataScope().equals(DataScopeType.ALL.getName())
                        || role.getDataScope().equals(DataScopeType.ORG_ALL.getName())).distinct().count();
                if (count > 0) {
                    orgScope = UserOperatorService.ORG_IDS;
                    orgIds[0] = UserOperatorService.DB_ORG_PARENT_ID;
                } else {
                    orgIds[0] = UserOperatorService.DB_ORG_ID;
                }
            }
        }
        orgIds[1] = currentOrgId;
        baseQuery.setOrgIds(orgIds);
        final String sql = UserOperatorService.buildDeptSql(orgScope, currentOrgId);
        sqlParam.setValue("(" + sql + ")");
        final List<SqlParam> list = Collections.singletonList(sqlParam);
        sysParams.put(UserOperatorService.DATA_SCOPE, UserOperatorService.sqlParamToString(list));
        sysParams.put(UserOperatorService.DATA_SCOPE_IN_SQL_COLUMN, UserOperatorService.buildColumnName(sqlParam));
        sysParams.put(UserOperatorService.DATA_SCOPE_IN_SQL_VALUE, sql);
        baseQuery.setSysParams(sysParams);
    }
}
